package com.atguigu.stgy.app.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.atguigu.stgy.app.service.UserInfoService;
import com.atguigu.stgy.common.consts.RedisPrefixConsts;
import com.atguigu.stgy.common.interceptor.StgyAuthInterceptor;
import com.atguigu.stgy.common.util.JwtUtils;
import com.atguigu.stgy.common.util.MobileNumberValidator;
import com.atguigu.stgy.model.dto.UserLoginDTO;
import com.atguigu.stgy.model.vo.SystemUserInfoVO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
//import javax.annotation.Resource;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.stgy.app.mapper.UserInfoMapper;
import com.atguigu.stgy.model.entity.UserInfo;
import org.springframework.util.StringUtils;

import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.random.RandomGenerator;

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    //阿里云短信平台可以设置发送频率、黑白名单
    //如果使用阿里云 云市场第三方的短信平台： 一般不会对频率进行限制
    @Override
    public void getCode(String phone) {
        //业务限制 保证短信接口的安全
        //1、手机号格式校验
        if(!MobileNumberValidator.isValidChineseMobileNumber(phone)){
            throw new RuntimeException("手机号格式错误");
        }
        //2、2分钟内相同手机号不能重复发送短信：防止表单重复提交
        if(stringRedisTemplate.hasKey(RedisPrefixConsts.APP_LOGIN_LIMIT_PRIFIX+phone)){
            throw new RuntimeException("请勿频繁获取验证码");
        }
        //3、一天内同一手机号最多获取5次验证码
        String countStr = stringRedisTemplate.opsForValue().get(RedisPrefixConsts.APP_LOGIN_COUNT_PRIFIX + phone);
        if(!StringUtils.isEmpty(countStr) && Integer.parseInt(countStr)>=5){
            throw new RuntimeException("验证码发送异常");
        }

        //4、发送短信
        try {
            String code = RandomUtil.randomNumbers(6);
//            //1、创建阿里云短信 的客户端对象：  客户端对象的作用可以访问阿里云短信服务 发送验证码给指定手机号
//            Config config = new Config();
////        config.setEndpoint() 设置阿里云服务器地址
//            config.setEndpoint("dysmsapi.aliyuncs.com");
//            // 如果使用阿里云短信平台 不是云市场的，配置的账号密码就是阿里云的账号密码，不推荐直接使用超级管理员账号
//            // 建议创建一个子账号，为他分配发送短信的权限 （注意：一定要保存子账户的 id和secret）
//            //账号  LTAI5tGxpGqaVFgsE2XnTJ5z
//            config.setAccessKeyId("LTAI5tGxpGqaVFgsE2XnTJ5z");
//            //密码  tl1PyVBxrMN7uiglS5Ia2NhyD7uxvh
//            config.setAccessKeySecret("tl1PyVBxrMN7uiglS5Ia2NhyD7uxvh");
//            Client client = new Client(config);
//            //2、封装请求对象： 发送短信的参数
//            SendSmsRequest sendSmsRequest = new SendSmsRequest()
//                    .setSignName("阿里云短信测试")
//                    .setTemplateCode("SMS_154950909") //短信模板：使用阿里云生成的默认的
//                    .setPhoneNumbers(phone) //必须是阿里云短信平台添加的手机号
//                    .setTemplateParam("{\"code\":\""+ code  +"\"}");//验证码
//            RuntimeOptions runtime = new RuntimeOptions();
//
//            // 复制代码运行请自行打印 API 的返回值
//            //3、使用客户端发送给短信 接受服务端的响应
//            SendSmsResponse smsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
//            //解析响应结果  根据code值判断响应是否成功
//            if (!"OK".equals(smsResponse.getBody().getCode())) {
//                throw new RuntimeException(smsResponse.getBody().getMessage());
//            }
            //短信发送成功
            //验证码缓存到redis:  过期时间20分钟
            stringRedisTemplate.opsForValue().set(RedisPrefixConsts.APP_LOGIN_CODE_PRIFIX+phone,code,
                    20 , TimeUnit.MINUTES);
            //5、更新手机号获取验证码的频率次数
            //5.1 2分钟内不能重复获取验证码
            stringRedisTemplate.opsForValue().set(RedisPrefixConsts.APP_LOGIN_LIMIT_PRIFIX+phone,"1",
                    2 , TimeUnit.MINUTES);
            //5.2 一天内只能发送五次验证码
//            if(stringRedisTemplate.hasKey(RedisPrefixConsts.APP_LOGIN_COUNT_PRIFIX+phone)){
//                //统计次数的key存在  基于之前的值+1
//                stringRedisTemplate.opsForValue().increment((RedisPrefixConsts.APP_LOGIN_COUNT_PRIFIX+phone));
//            }else{
//                //统计次数的key不存在  初始化为1 过期时间为一天
//                stringRedisTemplate.opsForValue().set(RedisPrefixConsts.APP_LOGIN_COUNT_PRIFIX+phone,"1",
//                        1 , TimeUnit.DAYS);
//            }
            if(stringRedisTemplate.opsForValue().increment((RedisPrefixConsts.APP_LOGIN_COUNT_PRIFIX+phone))==1L){
                //表示第一次设置count值 ， 需要设置过期时间
                stringRedisTemplate.expire(RedisPrefixConsts.APP_LOGIN_COUNT_PRIFIX+phone,1,TimeUnit.DAYS);
            }
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            // 错误 message
            System.out.println(error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        }


    }

    @Override
    public String login(UserLoginDTO userLoginDTO) {
        //1、校验手机号 和验证码
        String code = userLoginDTO.getCode();
        String phone = userLoginDTO.getPhone();
        if(!MobileNumberValidator.isValidChineseMobileNumber(phone) ||
        StringUtils.isEmpty(code)){
            throw new RuntimeException("参数错误");
        }
        //2、比较验证码：  手机号是否正确、以及验证码输入是否正确
        String cachedCode = stringRedisTemplate.opsForValue().get(RedisPrefixConsts.APP_LOGIN_CODE_PRIFIX + phone);
        if(!code.equals(cachedCode)){
            throw new RuntimeException("验证码错误");
        }
        //删除验证码: 获取验证码比较 和删除验证码分开执行的 不具有原子性  所以存在高并发安全问题
        stringRedisTemplate.delete(RedisPrefixConsts.APP_LOGIN_CODE_PRIFIX + phone);
        //3、查询用户数据
        UserInfo userInfo = this.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getPhone, phone));
        if(userInfo==null){
            //3.1 查询失败： 账号不存在  执行注册业务
            //初始化userInfo对象
            userInfo = new UserInfo();
            userInfo.setPhone(phone);
            userInfo.setPassword("12345");
            userInfo.setNickname("谷粉_"+ UUID.randomUUID().toString().substring(0,8));
            userInfo.setAvatarUrl("https://gitee.com/static/images/logo-black.svg?t=158106664");
            userInfo.setStatus((byte) 1);
            this.save(userInfo); //新增时 mp会自动生成用户id
        }else{
            //3.2 查询成功： 账号存在  登录成功  执行登录成功业务
            if(userInfo.getStatus().intValue()!=1){
                throw new RuntimeException("用户账户锁定");
            }
        }
        //返回登录状态的jwt
        //4、创建 jwt的token： userInfo的数据一定不为空 都初始化了
        return JwtUtils.buildToken(userInfo.getNickname() , userInfo.getId());
    }

    @Override
    public SystemUserInfoVO getInfo() {
        //解析jwt
//        Jws<Claims> claimsJws = JwtUtils.parseToken(token);
//        Long id = claimsJws.getBody().get("id",Long.class);
        //获取 拦截器透传的用户id使用
//        Long id = StgyAuthInterceptor.AUTH_MAP.get(Thread.currentThread());
        Long id = StgyAuthInterceptor.THREAD_LOCAL.get();
        UserInfo userInfo = this.getById(id);
        SystemUserInfoVO vo = new SystemUserInfoVO();
        vo.setNickname(userInfo.getNickname());
        vo.setAvatarUrl(userInfo.getAvatarUrl());
        return vo;
    }

}
